package com.foreveross.push.socket;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import com.foreveross.bsl.util.Preferences;
import com.foreveross.push.nodeclient.NotificationPacketListener;
import com.foreveross.push.nodeclient.PackageUtil;
import com.foreveross.push.socket.SocketConnect.SocketMsgHandler;
import com.foss.AppLog;
import com.foss.ChameleonApplication;
import com.foss.DeviceInfoUtil;
import com.foss.GeneralUtils;
import com.foss.mdm.MdmHandlerEntry;
import org.jivesoftware.smack.packet.Message;
import org.json.JSONException;
import org.json.JSONObject;
import org.msgpack.MessagePack;
import org.msgpack.type.Value;

import java.io.IOException;
import java.util.ArrayList;

/**
 * project:
 * author: wzq
 * date: 2014/7/22
 * description: 使用socket 发送、接收消息，并处理接收到的消息
 */
public class PushRTx {
    private static final int HEARTBEAT_CYCLE = 5 * 60 * 1000;//定时任务时间间隔
    private static final int MAX_HEART_TRY_TIME = 3;//心跳最大尝试次数

    private static int countHeartSend = 0;
    private static int countHeartResp = 0;

    private static SocketConnect socket;
    // 停止收发:关闭定时任务,清理
    public static void stopRTx() {
        if(socket != null) {
            //AppLog.i("stopRTx");
            countHeartSend = 0;
            countHeartResp = 0;
            heartSendTime.clear();
            stopTimerHeartBeat();
            socket = null;
        }
    }


    /** 开始收发:首先发送一个对象，收到回复后，发送心跳 */
    public static void startRTx(SocketConnect s, String token) {
        stopRTx();
        //
        socket = s;
        s.setSocketMsgHandler(msgHandler);
        sendEntity(token);
    }

    private static void sendEntity(String token) {
        AuthMessageEntity entity = new AuthMessageEntity();
        entity.setDeviceId(DeviceInfoUtil.getDeviceId());
        entity.setPushToken(token);
        String username = Preferences.getUserName();
        if(username == null || username.equals("")) {
            username = "guest";
        }
        entity.setUserName(username);
        try {
            byte[] msg = PackageUtil.ToByte(entity);
            AppLog.i("socket 发送对象" + entity.toString());
            socket.sendMsg(msg);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    /** 收到消息，统一处理 入口 */
    private static SocketMsgHandler msgHandler = new SocketMsgHandler() {
        @Override
        public void onReceiveMsg(byte[] msg) {
            //AppLog.i("收到 socket 信息" + CryptUtils.printByteArray(msg));
            // TODO:处理数据入口
            if(isHeartReply(GeneralUtils.copyBytes(msg))) {
                AppLog.i("是 心跳包");
                handleMsgHeartReply();
                return;
            }

            // 是否entity reply
            Object entityReply = getEntityReply(GeneralUtils.copyBytes(msg));
            if(entityReply != null) {
                handleEntityReply((Boolean) entityReply);
                return;
            }

            // mdm
            JSONObject jsonMdm = isMdmMsg(GeneralUtils.copyBytes(msg));
            if(jsonMdm != null) {
                AppLog.i("收到 MDM");
                new MdmHandlerEntry(jsonMdm).handleMdm();
                return;
            }

            // 常规 push信息
            AppLog.i("普通 push信息");
            handleNormalMsg(msg);
        }
    };

    /**
     * TODO:判断是否为mdm信息,如果是，则处理
     * @param bytes
     * @return null 表示非mdm信息,非null表示是mdm信息 messageType: “MDM”
     */
    private static JSONObject isMdmMsg(byte[] bytes) {
        try {
            Value v = PackageUtil.byteToObject(bytes);
            JSONObject jsonObj = new JSONObject(v.toString());
            if(jsonObj.has(MESSAGE_TYPE_KEY)) {
                if(MESSAGE_TYPE_MDM.equals(jsonObj.getString(MESSAGE_TYPE_KEY))) {
                    return jsonObj;
                }
            }
        } catch(JSONException e) {
            // 无须处理，非mdm json
        }
        return null;
    }
    private static String MESSAGE_TYPE_KEY = "messageType";
    private static String MESSAGE_TYPE_MDM = "MDM";
    // 普通消息，先解析成JSON,再处理
    private static void handleNormalMsg(byte[] bytes) {
        try {
            Value v = PackageUtil.byteToObject(bytes);
            JSONObject jsonObj = new JSONObject(v.toString());
            if(jsonObj.has("id")) { // 含有id,普通push信息
                String id = jsonObj.getString("id");
                if(null == id && "".equals(id)) {
                    AppLog.e("push数据含有id字段，但是id为空");
                } else {
                    // 去拉取信息
                    NotificationPacketListener.processPacket(new Message());
                }
            } else {
                AppLog.e("不识别(未处理)的push信息:" + jsonObj.toString());
            }
        } catch(JSONException e) {
            AppLog.e("非心跳，push数据无法解析成json");// 格式错误
        }
    }

    // 心跳得到回应
    private static void handleMsgHeartReply() {
        countHeartResp++;
        AppLog.i("发送心跳次数 =" + countHeartSend + ", 收到心跳回复 =" + countHeartResp);
        heartSendTime.clear();
    }

    /** 处理entity 回应 ， isTrue 响应的 result = isTrue */
    private static void handleEntityReply(boolean isTrue) {
        if(isTrue) { // 响应正确
            startTimerHeartBeat();
        } else {// 响应错误,表明上送数据不正确，清理token
            TokenGetter.clearCurrToken();
            stopRTx();
            PushSetup.getInstance().socketRTxErr();
        }
    }

    /**
     * 是否 entity的回应,如果是，则返回内容，不是则返回null
     */
    private static Object getEntityReply(byte[] bytes) {
        try {
            Value v = PackageUtil.byteToObject(bytes);
            JSONObject jsonObj = new JSONObject(v.toString());
            boolean r = jsonObj.getBoolean("result");
            return r;
        } catch(JSONException e) {
            // 不需要处理,这个数据不是 entity的回复
        }
        return null;
    }
    /** 定时器发送的 intent */
    private static PendingIntent timerIntent;
    private static PendingIntent getTimerIntent() {
        if(timerIntent == null) {
            Context context = ChameleonApplication.getApplication();
            Intent intent = new Intent(context, SendHeartbeatReceiver.class);
            intent.setAction("heartbeat.receiver");
            timerIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        }
        return timerIntent;
    }

    /** 启动定时任务:心跳 */
    private static void startTimerHeartBeat() {
        //AppLog.i("启动心跳:startTimerHeartBeat");
        Context context = ChameleonApplication.getApplication();
        AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
        am.setRepeating(AlarmManager.RTC_WAKEUP, SystemClock.elapsedRealtime(), HEARTBEAT_CYCLE, getTimerIntent());
    }

    /** 结束定时任务:心跳 */
    private static void stopTimerHeartBeat() {
        //AppLog.i("停止心跳:stopTimerHeartBeat");
        Context context = ChameleonApplication.getApplication();
        if(timerIntent != null) {
            AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
            am.cancel(timerIntent);
            timerIntent = null;
        }
    }

    /** 单次心跳发送 */
    private static void heartOneTime() {
        if(heartSendTime.size() >= MAX_HEART_TRY_TIME) {// 已经有超过失败限额
            stopRTx();
            PushSetup.getInstance().socketRTxErr();
        } else {
            if(socket != null && socket.isAvailiable()) {
                // 增加一条心跳发送记录，该记录等待回应
                heartSendTime.add(SystemClock.currentThreadTimeMillis());
                byte[] heartSend = PackageUtil.ToByteNoJson("");
                socket.sendMsg(heartSend);
                countHeartSend++;
            } else {
                // socket已经无效了
                stopRTx();
                PushSetup.getInstance().socketRTxErr();
            }
        }
    }
    // 未响应的心跳记录，如果响应了，则清零
    private static ArrayList<Long> heartSendTime = new ArrayList<Long>();


    /** 定时器发送的 心跳广播,收到心跳广播后，发送心跳 */
    public static class SendHeartbeatReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //AppLog.d("SendHeartbeatReceiver::AlarmReceiver 收到广播 from Alarmer");
            heartOneTime();
        }
    }

    /** 判断是否为心跳回执 */
    private static boolean isHeartReply(byte[] btyes) {
        // 生成正确的心跳回应,
        byte[] right = {};
        try {
            byte b = new MessagePack().write("")[0];
            byte[] a = {0, 0, 0, 1, 1, b};
            right = a;
        } catch(IOException e) {
            e.printStackTrace();
        }

        // 比较
        if(btyes.length != right.length) {
            return false;
        }
        for(int i = 0; i < btyes.length; i++) {
            if(btyes[i] != right[i]) {
                return false;
            }
        }
        return true;
    }

}
